import { useSelector, useDispatch } from 'react-redux';
import * as store from './reducers/partsSlice';
import React from 'react';
import MyHidden from "./MyHidden";
import funcs from './js/util/funcs';
import places from './js/places/places.js';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import Accordion from '@mui/material/Accordion';
import AccordionSummary from '@mui/material/AccordionSummary';
import AccordionDetails from '@mui/material/AccordionDetails';
import formatRelativeDate from './js/util/relativeDate.js';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import classNames from 'classnames';
import StarIcon from '@mui/icons-material/Star';
import Tooltip from '@mui/material/Tooltip';
import IconButton from '@mui/material/IconButton';
import Button from '@mui/material/Button';
import DeleteIcon from '@mui/icons-material/Delete';
import Checkbox from '@mui/material/Checkbox';
import FormControlLabel from '@mui/material/FormControlLabel';
import { db } from './js/util/database.js';
const electron = window.require("electron");
const fs = window.require("fs");
var results = {}; // format is {pluginName: [results]}
var URLHandlers = []; // format is {trigger, action}
var lastItemDeletion = Date.now();
var topAnswer = {
  plugin: null,
  item: null,
};
const maxTagSuggestions = 12;
function TagElement(props) {
  const [state, setState] = React.useState({ checked: props.selected });
  const handleChange = (event) => {
    // setChecked(event.target.checked);
    console.log('TagElement onClick');
    if (props.onclick_func != null) {
      console.log('props.onclick_func');
      props.onclick_func();
    }
  };
  console.log("Tag --------------");
  console.log(state, props);
  return (
    <FormControlLabel
      control={<Checkbox checked={props.selected}
        onChange={handleChange} />} label={props.tag} />);
}

class BookmarkEditor extends React.Component {
  constructor(props) {
    super();
    this.state = { suggested: [], ct: 0 };
    // BookmarkEditor.current = this;
  }
  componentDidMount = () => {
    this.changed = false;
    let bookmark = this.props.bookmark;
    places.getSuggestedTags(bookmark.url, (suggestions) => {
      this.setState({ suggested: suggestions });
    });
  };
  render() {
    // console.log(this.props);
    let bookmark = this.props.bookmark;
    if (bookmark == null) return <div>null</div>;
    let options = this.props.options;
    let cn = classNames('bookmark-editor', 'searchbar-item', {
      simplified: options.simplified,
    });
    let tag_eles = bookmark.tags.map((tag, idx) => {
      console.log(tag, idx);
      return (
        <TagElement
          key={idx}
          tag={tag}
          selected={true}
          onclick_func={() => {
            console.log('onclick_func===');
            places.toggleTag(bookmark.url, tag);
            bookmark.tags.splice(idx, 1);
            this.changed = true;
            this.setState((state) => ({ ct: state.ct + 1, ...state }));
          }}
        />
      );
    });
    let tagSugg_eles = this.state.suggested
      .filter((tag, idx) => {
        return (
          this.state.suggested.indexOf(tag) === idx &&
          !bookmark.tags.includes(tag)
        );
      })
      .slice(0, 3)
      .map((tag, idx) => {
        return (
          <TagElement
            tag={tag}
            key={idx}
            selected={false}
            onclick_func={() => {
              places.toggleTag(bookmark.url, tag);
            }}
          />
        );
      });
    // newTagInput.className = 'tag-input';
    // newTagInput.placeholder = l('bookmarksAddTag');
    // newTagInput.classList.add('mousetrap');
    // newTagInput.spellcheck = false;
    // if (options.autoFocus) {
    //   newTagInput.focus();
    // }
    var tagArea = (
      <div className="tag-edit-area">
        {tag_eles}
        {tagSugg_eles}
        <input
        className="tag-input mousetrap"
        onChange={(e) => { }}
        onKeyPress={(e) => {
          // console.log(e);
          if (e.charCode !== 8 && e.charCode !== 13) {
            // places.getAllTagsRanked(bookmark.url, results => {
            //   // autocomplete.autocomplete(newTagInput, results.map(r => r.tag));
            // });
          }
          if (e.charCode == 13) {
            var val = e.target.value;
            if (!bookmark.tags.includes(val)) {
              places.toggleTag(bookmark.url, val);
              bookmark.tags.push(val);
              this.changed = true;
              this.setState((state) => ({ ct: state.ct + 1, ...state }));
            }
          }
        }}
        placeholder={'bookmarksAddTag'}
      ></input>
      </div>
    );
    return (
      <ListItem className={cn} hidden={this.props.hidden}>
        {tagArea}
        <Tooltip title="delete bookmark" placement="top">
          <IconButton
            className="action-button always-visible bookmark-delete-button i carbon:delete"
            tabIndex={-1}
            onClick={() => {
              console.log('delete');
              places.toggleBookmarked_url(bookmark.url);
              this.props.remove();
            }}
          ><DeleteIcon />
          </IconButton>
        </Tooltip>
      </ListItem>
    );
  }
}

function BookMarkItem(props) {
  const [state, setState] = React.useState({ hidden: false });
  return (<Accordion style={{ display: state.hidden ? "none" : "inline" }}>
    <AccordionSummary
      expandIcon={<ExpandMoreIcon />}
      aria-controls="panel2a-content"
      id="panel2a-header"
    >
      <BookMarkItemShow
        openURL={props.openURL}
        result={props.result}
        focus={props.focus}
      />
    </AccordionSummary>
    <AccordionDetails>
      <BookmarkEditor
        remove={() => {
          setState({ hidden: true });
        }}
        options={{ simplified: false }}
        bookmark={props.result}
        focus={props.focus}
      />
    </AccordionDetails>
  </Accordion>);
}
function BookMarkItemShow(props) {
  const dispatch = useDispatch();
  console.log("BookMarkItemShow");
  let data = {
    title: props.result.title,
    icon: 'carbon:star-filled',
    secondaryText: urlParser.getSourceURL(props.result.url),
    fakeFocus: props.focus,
  };
  let cn = classNames(
    'searchbar-item',
    'has-action-button',
    'bookmark-item',
    { fakefocus: data.fakeFocus }
  );
  let childs = [];
  let key = 0;
  if (data.icon) {
    childs.push(<StarIcon key={key++} />);
  }

  if (data.title) {
    let cn_ti = classNames('title', { wide: !data.secondaryText });
    childs.push(
      <span key={key++} className={cn_ti}>
        {data.title.substring(0, 100)}
      </span>
    );
  }
  return (
    <ListItem
      style={{
        display: "flex",
      }}
      onClick={e => {
        console.log("onclick");
        dispatch(store.partsSlice.actions.OPEN_URL(props.result.url));
      }}
      className={cn}
      tabIndex={-1}
    >
      {childs}
      <a href={props.result.url}>{props.result.url.substring(0, 100)}</a>
    </ListItem>
  );
}

export default function BookMark(props) {
  console.log("BookMark--------------------------------")
  console.log(props)
  const dispatch = useDispatch();
  const [state, setState] = React.useState({ container: [] });
  React.useEffect(() => {
    showBookmarks2('');
  }, [])
  showBookmarks2 = (text) => {
    console.log('showBookmarks========');
    console.log(text);
    var parsedText = funcs.parseBookmarkSearch(text);
    console.log(parsedText);
    var displayedURLset = [];
    places.searchPlaces(
      parsedText.text,
      (results) => {
        places.autocompleteTags(parsedText.tags, (suggestedTags) => {
          console.log("///////////////////////////");
          console.log(parsedText.tags);
          console.log(suggestedTags);
          state.container = [];
          let tag_eles = parsedText.tags.map((tag, idx) => {
            return (
              <TagElement
                tag={tag}
                key={idx}
                selected={true}
                onclick_func={() => {
                  showBookmarks2(text.replace('#' + tag, '').trim());
                }}
              />
            );
          });

          // it doesn't make sense to display tag suggestions if there's a search, since the suggestions are generated without taking the search into account
          // if (!parsedText.text) {
          suggestedTags.forEach((suggestion, index) => {
            let key = tag_eles.length;
            var el = (
              <TagElement
                key={key}
                tag={suggestion}
                selected={false}
                onclick_func={() => {
                  var needsSpace =
                    text.slice(-1) !== ' ' && text.slice(-1) !== '';
                  showBookmarks2(
                    text +
                    (needsSpace ? ' #' : '#') +
                    suggestion +
                    ' '
                  );
                }}
              />
            );
            tag_eles.push(el);
          });

          if (suggestedTags.length > maxTagSuggestions) {
            let key = tag_eles.length;
            var expandEl = (
              <TagElement
                key={key}
                tag={'\u2026'}
                selected={false}
                onclick_func={() => {
                  //todo
                  // tagBar.classList.add('expanded');
                  // expandEl.remove();
                }}
              />
            );
            tag_eles.push(expandEl);
          }
          // }
          let key = state.container.length;
          var tagBar = (
            <div key={key} id="bookmark-tag-bar">
              {tag_eles}
            </div>
          );
          state.container.push(tagBar);
          var lastRelativeDate = ''; // used to generate headings
          // let key=0;
          let items = [];
          let item_at = 0;
          console.log("results:", results);
          results
            .filter((result) => {
              if (funcs.itemMatchesTags(result, parsedText.tags)) {
                return true;
              } else {
                return false;
              }
            })
            .sort((a, b) => {
              // order by last visit
              return b.lastVisit - a.lastVisit;
            })
            .slice(0, 100)
            .forEach((result, index) => {
              displayedURLset.push(result.url);
              var thisRelativeDate = formatRelativeDate(result.lastVisit);
              if (thisRelativeDate !== lastRelativeDate) {
                lastRelativeDate = thisRelativeDate;
              }
              let item = (
                <BookMarkItem openURL={() => {
                  this.props.dispatch(store.partsSlice.actions.OPEN_URL(url));
                }}
                  key={item_at}
                  result={result}
                  focus={index === 0 && parsedText.text}
                />
              );
              items.push(item);
              item_at += 1;
            });
          key = state.container.length;
          state.container.push(<List key={key}>{items}</List>);
          key = state.container.length;
          if (parsedText.tags.length > 0) {
            places.getSuggestedItemsForTags(
              parsedText.tags,
              function (suggestedResults) {
                suggestedResults = suggestedResults.filter(
                  (res) => !displayedURLset.includes(res.url)
                );
                if (suggestedResults.length === 0) {
                  return;
                }
                addHeading('bangs', {
                  text: l('bookmarksSimilarItems'),
                });
                suggestedResults
                  .sort(function (a, b) {
                    // order by last visit
                    return b.lastVisit - a.lastVisit;
                  })
                  .forEach((result, index) => {
                    let key = state.container.length;
                    let item = (
                      <BookMarkItem openURL={() => {
                        this.props.dispatch(store.partsSlice.actions.OPEN_URL(url));
                      }} key={key} result={result} focus={false} />
                    );
                    state.container.push(item);
                  });
              }
            );
          }
          setState((state) => ({ container: state.container }));
        });
      },
      {
        searchBookmarks: true,
        limit: Infinity,
      }
    );
  };
  const importBook = () => {
    var options = {
      properties: ['openFile'],
      filters: [{ name: 'HTML files', extensions: ['htm', 'html'] }],
    };
    electron.ipcRenderer
      .invoke('showOpenDialog', options)
      .then((res) => {
        console.log(res);
        if (res.length == 0) return;
        fs.readFile(res[0], 'utf-8', (err, data) => {
          if (err || !data) {
            console.warn(err);
            return;
          }
          var tree = new DOMParser().parseFromString(data, 'text/html');
          var bookmarks = Array.from(tree.getElementsByTagName('a'));
          bookmarks.forEach((bookmark) => {
            var url = bookmark.getAttribute('href');
            if (
              !url ||
              (!url.startsWith('http:') &&
                !url.startsWith('https:') &&
                !url.startsWith('file:'))
            ) {
              return;
            }

            var data = {
              title: bookmark.textContent,
              isBookmarked: true,
            };
            try {
              data.lastVisit =
                parseInt(bookmark.getAttribute('add_date')) * 1000;
            } catch (e) { }
            var parent = bookmark.parentElement;
            while (parent != null) {
              if (parent.children[0] && parent.children[0].tagName === 'H3') {
                data.tags = [
                  parent.children[0].textContent.replace(/\s/g, '-'),
                ];
                break;
              }
              parent = parent.parentElement;
            }
            console.log(url, data);
            places.updateItem(url, data, () => {
              console.log("updateItem ok")
            });
          });
        });
      })
      .catch((e) => {
        console.log(e);
      });
  }
  const clearBook = () => {
    let items = []
    db.places
      .each((item) => {
        if (item.isBookmarked) {
          items.push(item)
        }
      })
      .then(() => {
        items.map((item) => {
          places.toggleBookmarked_url(item.url, item.title, (isBookmarked) => {
            // dispatch(store.partsSlice.actions.CLICK_STAR(isBookmarked));
          });
        })
      });
  }
  const exportBook = () => {
    // build the tree structure
    var root = document.createElement('body');
    var heading = document.createElement('h1');
    heading.textContent = 'Bookmarks';
    root.appendChild(heading);
    var innerRoot = document.createElement('dl');
    root.appendChild(innerRoot);

    var folderRoot = document.createElement('dt');
    innerRoot.appendChild(folderRoot);
    var folderHeading = document.createElement('h3');
    folderHeading.textContent = 'Min Bookmarks';
    folderRoot.appendChild(folderHeading);
    var folderBookmarksList = document.createElement('dl');
    folderRoot.appendChild(folderBookmarksList);

    db.places
      .each(function (item) {
        if (item.isBookmarked) {
          var itemRoot = document.createElement('dt');
          var a = document.createElement('a');
          itemRoot.appendChild(a);
          folderBookmarksList.appendChild(itemRoot);

          a.href = urlParser.getSourceURL(item.url);
          a.setAttribute('add_date', Math.round(item.lastVisit / 1000));
          a.textContent = item.title;
          // Chrome will only parse the file if it contains newlines after each bookmark
          var textSpan = document.createTextNode('\n');
          folderBookmarksList.appendChild(textSpan);
        }
      })
      .then(() => {
        // save the result
        // var savePath = electron.remote.dialog.showSaveDialogSync({ defaultPath: 'bookmarks.html' })
        var options = {
          defaultPath: 'bookmarks.html',
          filters: [{ name: 'HTML files', extensions: ['htm', 'html'] }],
        };
        electron.ipcRenderer
          .invoke('showSaveDialog', options)
          .then((res) => {
            console.log(res);
            if (!res) return;
            let savePath = res;
            window.require('fs').writeFileSync(savePath, root.outerHTML);
          })
          .catch((e) => {
            console.log(e);
          });
      });
  }
  return (
    <MyHidden title="bookmarks" on_hidden={() => {
      dispatch(store.partsSlice.actions.SHOW_BOOK(false))
    }} hidden={!useSelector((state) => state.show_book)}>
      {state.container}
      <Button
        onClick={() => {
          importBook();
        }}
      >
        Import Bookmarks
      </Button>
      <Button
        onClick={() => {
          exportBook();
        }}
      >
        Export Bookmarks
      </Button>
      <Button
        onClick={() => {
          clearBook();
        }}
      >
        Clear Bookmarks
      </Button>
    </MyHidden>
  );
}
